/*********************
 *      INCLUDES
 *********************/

#include "compass_app.h"
#include <rtdevice.h>
#include "littlevgl2rtt.h"
#include "lvsf_comp.h"
#include "gui_app_fwk.h"
#include "lv_ext_resource_manager.h"
#include "lv_ex_data.h"
#include "app_mem.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "sensor_memsic_mmc56x3.h"
#include "bf0_hal.h"
#include "drv_io.h"
#include "drv_gpio.h"

#include <i2c.h>

/*********************
 *      DEFINES
 *********************/
#define APP_ID "compass"

// 指南针尺寸定义
#define COMPASS_SIZE 300
#define POINTER_SIZE 200
#define INFO_HEIGHT 60

// 声明图标
LV_IMG_DECLARE(img_compass);
LV_IMG_DECLARE(compass_dial_diagram);
LV_IMG_DECLARE(compass_pointer_diagram);

/*********************
 *  STATIC VARIABLES
 *********************/
static lv_obj_t *main_cont = NULL;
static lv_obj_t *direction_label = NULL;

// 指南针数据
static float current_angle = 0.0f;
static float smoothed_angle = 0.0f;
static float last_smoothed_angle = 0.0f;
static rt_bool_t first_measurement = RT_TRUE;
static const float EMA_ALPHA = 0.2f;

// 全局变量定义
Compass *r_dial = NULL;
lv_obj_t *angle_label = NULL;
lv_obj_t *char_label = NULL;
float current_angle_360 = 0.0f;

// 传感器相关
static rt_device_t mmc56x3_dev = NULL;
static struct rt_sensor_data mmc56x3_data;



/*********************
 *  STATIC PROTOTYPES
 *********************/
static void create_compass_ui(void);
static void create_direction_marks(lv_obj_t *parent);
static float read_sensor_angle(void);
static float normalize_angle(float angle);
static int get_direction_index(float angle);
// static void init_sensor(void);  // 移除这行，因为init_sensor需要在外部访问
static void deinit_sensor(void);

/*********************
 *   STATIC FUNCTIONS
 *********************/

/**
 * @brief 根据角度获取方向索引
 * @param angle 角度值
 * @return 方向索引（0-7）
 */
static int get_direction_index(float angle)
{
    // 将角度转换到0-360范围
    float normalized = fmodf(angle + 360.0f, 360.0f);
    
    // 每个方向45°范围
    if (normalized >= 337.5f || normalized < 22.5f) return 0;    // 北
    else if (normalized >= 22.5f && normalized < 67.5f) return 1;  // 东北
    else if (normalized >= 67.5f && normalized < 112.5f) return 2; // 东
    else if (normalized >= 112.5f && normalized < 157.5f) return 3; // 东南
    else if (normalized >= 157.5f && normalized < 202.5f) return 4; // 南
    else if (normalized >= 202.5f && normalized < 247.5f) return 5; // 西南
    else if (normalized >= 247.5f && normalized < 292.5f) return 6; // 西
    else return 7; // 西北
}

/**
 * @brief 初始化传感器
 */
void init_sensor(void)
{
    // 初始化硬件I/O - 使用I2C3而不是I2C2，根据proj.conf配置
    HAL_PIN_Set(PAD_PA40, I2C3_SCL, PIN_PULLUP, 1);
    HAL_PIN_Set(PAD_PA39, I2C3_SDA, PIN_PULLUP, 1);
    
    // 初始化传感器配置
    struct rt_sensor_config cfg;
    cfg.intf.dev_name = "i2c3";  // 修改为i2c3
    rt_hw_mmc56x3_init("mmc56x3", &cfg);
    
    // 查找并打开传感器设备
    mmc56x3_dev = rt_device_find("mag_mmc56x3");
    if (mmc56x3_dev != RT_NULL) 
    {
        rt_err_t result = rt_device_open(mmc56x3_dev, RT_DEVICE_FLAG_RDONLY);//在这个框架内只读模式他设置的是轮询模式
        rt_kprintf("Compass sensor opened with result: %d\n", result);
        if (result != RT_EOK) {
            rt_kprintf("Failed to open compass sensor, error: %d\n", result);
            mmc56x3_dev = RT_NULL;  // 确保设备指针在打开失败时为NULL
        }
    } 
    else
    {
        rt_kprintf("Failed to find compass sensor!\n");
    }
    //新加的，来测试是不是这样可以读取到新的数据
    if (mmc56x3_dev != RT_NULL)
    {
        // 获取I2C总线设备（mmc56x3_dev->bus 是I2C总线指针）
        struct rt_i2c_bus_device *i2c_bus = rt_i2c_bus_device_find("i2c3");
        if(i2c_bus == RT_NULL)
        {
            rt_kprintf("failed to find i2c3 bus\r\n");
            return;
        }

        uint8_t i2c_addr = 0x30; // MMC56x3的7位I2C地址
        uint8_t cmd[2];

        // 步骤1：配置连续测量模式（0x09寄存器 = 0x01）
        cmd[0] = 0x09;
        cmd[1] = 0x01;
         rt_i2c_mem_write(i2c_bus, i2c_addr, RT_NULL, 0, cmd, 2);
        rt_thread_mdelay(10); // 延时确保配置生效

        // 步骤2：配置采样频率（0x0A寄存器 = 0x0A → 10Hz）
        cmd[0] = 0x0A;
        cmd[1] = 0x0A;
         rt_i2c_mem_write(i2c_bus, i2c_addr, RT_NULL, 0, cmd, 2);
        rt_thread_mdelay(10);

        rt_kprintf("MMC56x3 configured to continuous mode (10Hz)\n");
    }


}

/**
 * @brief 反初始化传感器
 */
void deinit_sensor(void)
{
    if (mmc56x3_dev != NULL) {
        rt_device_close(mmc56x3_dev);//关闭定时器
        mmc56x3_dev = NULL;
    }
}

/**
 * @brief  角度归一化函数（将任意角度转换到-180° ~ 180°范围）
 * @param  angle - 待归一化的原始角度（单位：°）
 * @retval 归一化后的角度（-180° ~ 180°）
 */
static float normalize_angle(float angle)
{
    // 对360取模，先将角度转换到0° ~ 360°范围
    angle = fmod(angle, 360.0f);
    // 若角度大于180°，减去360°，转换到-180° ~ 180°
    if (angle > 180.0f) angle -= 360.0f;
    // 若角度小于-180°，加上360°，转换到-180° ~ 180°
    if (angle < -180.0f) angle += 360.0f;
    return angle;
}

/**
 * @brief  设置图片缩放比例（避免图片拉伸，适配目标尺寸）
 * @param  obj_img - 图片对象指针
 * @param  src - 图片资源（如&compass_dial_diagram）
 * @param  obj_width - 目标宽度
 * @param  obj_height - 目标高度
 * @retval 无
 */
static void lv_obj_img_png_set_zoom(lv_obj_t *obj_img, const void *src, uint32_t obj_width, uint32_t obj_height)
{
    // 检查参数
    if (obj_img == NULL || src == NULL) {
        rt_kprintf("Invalid parameters for zoom function\n");
        return;
    }
    
    // 存储图片原始宽高、缩放因子（LVGL缩放单位：256=原尺寸，512=2倍缩放）
    uint32_t img_width = 0, img_height = 0, zoom_factor = 0;
    // LVGL图片头结构体（存储图片宽高、格式等信息）
    lv_img_header_t header;

    // 1. 获取图片头信息（失败则打印错误）
    if (lv_img_decoder_get_info(src, &header) != LV_RES_OK)
    {
        rt_kprintf("lv_img_decoder_get_info error\n");
        return;
    }

    // 2. 提取图片原始宽高
    img_width = header.w;
    img_height = header.h;

    // 3. 调试打印图片原始尺寸与目标尺寸
    rt_kprintf("img_width:%u, img_height:%u, obj_width:%u, obj_height:%u\n", img_width, img_height, obj_width, obj_height);

    // 4. 计算缩放因子（取宽高比例中的较小值，避免图片拉伸）
    if (img_width != 0 && img_height != 0)
    {
        uint32_t y_a = obj_height; // 目标高度
        uint32_t x_b = obj_width;  // 目标宽度

        // 若目标宽度 >= 目标高度，按高度比例缩放（避免高度超出）
        if (x_b >= y_a)
        {
            // 缩放因子 = (目标高度 * 256) / 原始高度（LVGL缩放单位）
            uint32_t x = obj_height * 256;
            zoom_factor = x / img_height;
            lv_img_set_zoom(obj_img, zoom_factor);
        }
        // 若目标宽度 < 目标高度，按宽度比例缩放（避免宽度超出）
        else
        {
            // 缩放因子 = (目标宽度 * 256) / 原始宽度
            uint32_t x = obj_width * 256;
            zoom_factor = x / img_width;
            lv_img_set_zoom(obj_img, zoom_factor);
        }
    }
}

/**
 * @brief  分配并初始化指南针指针图片资源（避免图片数据重复占用内存）
 */
static void handle_img(void)
{
    // 检查必要的指针
    if (r_dial == NULL) {
        rt_kprintf("Compass dial is NULL\n");
        return;
    }
    
    // 1. 分配指针图片描述符内存（大小与compass_pointer_diagram一致）
    lv_img_dsc_t *img_dos = (lv_img_dsc_t *) rt_malloc(sizeof(compass_pointer_diagram));
    if (img_dos == NULL)
    {
        rt_kprintf("rt_malloc fail (img_dos)\n");
        return;
    }

    // 2. 分配指针图片数据内存（大小与图片原始数据一致）
    uint8_t *img_data_size = (uint8_t *)rt_malloc(compass_pointer_diagram.data_size);
    if (img_data_size == NULL)
    {
        rt_kprintf("rt_malloc fail (img_data_size)\n");
        rt_free(img_dos); // 释放已分配的描述符内存，避免内存泄漏
        return;
    }

    // 3. 复制原始图片数据到新分配的内存
    memcpy(img_data_size, compass_pointer_diagram.data, compass_pointer_diagram.data_size);

    // 4. 初始化图片描述符（复制原始描述符信息，更新数据指针）
    *img_dos = compass_pointer_diagram;
    img_dos->data = img_data_size;

    // 5. 将图片描述符赋值给指南针实例
    r_dial->cp_point = img_dos;

    // 6. 若指针对象已创建，设置指针图片源
    if (r_dial->compass_pointer != NULL)
    {
        lv_img_set_src(r_dial->compass_pointer, r_dial->cp_point);
    }
}

/**
 * @brief 读取传感器角度数据
 * @return 平滑处理后的角度值（度）
 */
float read_sensor_angle(void)
{
    // 检查指针是否为空
    // 注释原因：保留对compass_pointer的检查以保持向后兼容性，尽管不再使用指针
    if (r_dial == NULL /* || r_dial->compass_pointer == NULL */) {
        rt_kprintf("UI elements not initialized\n");
        return 0.0f;
    }
    
    //设备初始化之后正常就不为空
    if (mmc56x3_dev == NULL) {
        rt_kprintf("Sensor device is NULL, returning 0.0f\n");
        // 临时使用模拟数据进行测试
        static float test_angle = 0.0f;
        test_angle += 5.0f; // 每次增加5度
        if (test_angle >= 360.0f) test_angle = 0.0f;
        return test_angle;
    }
    
    // 读取传感器数据
    rt_size_t res = rt_device_read(mmc56x3_dev, 0, &mmc56x3_data, 1);
    if (res == 0) {
        rt_kprintf("Failed to read sensor data, returning current angle\n");
        return current_angle; // 读取失败返回上次角度
    }
    rt_kprintf("Before data check: mag.x=%d, mag.y=%d\n", 
           mmc56x3_data.data.mag.x, mmc56x3_data.data.mag.y);
    // 检查传感器数据是否有效
    if (mmc56x3_data.data.mag.x == 0 && mmc56x3_data.data.mag.y == 0) {
        rt_kprintf("Invalid sensor data (both x and y are zero)\n");
        return current_angle;
    }
    
    // 计算原始角度（atan2结果转换为度）
    //得到的结果是设备的X轴正方向和磁北方向的夹角  0--就是北方  90--就是东方  -90--就是西方-180--就是南方
    float raw_angle = atan2f((float)mmc56x3_data.data.mag.y, (float)mmc56x3_data.data.mag.x) * 180.0f / M_PI;
    
    rt_kprintf("Raw sensor angle: %.2f\n", raw_angle);

    // 处理首次测量
    if (first_measurement) {
        smoothed_angle = raw_angle;//平滑角度
        last_smoothed_angle = smoothed_angle;//上一次的平滑角度
        first_measurement = RT_FALSE;
        rt_kprintf("First measurement, initializing smoothed angle: %.2f\n", smoothed_angle);
        return smoothed_angle;
    }

    // 计算角度差（解决180°边界问题，如170°到-170°，实际差为-40°而非340°）
    float angle_diff = raw_angle - last_smoothed_angle;
    // 角度差归一化（确保差在-180° ~ 180°，避免边界跳变）
    if (angle_diff > 180.0f) angle_diff -= 360.0f;
    if (angle_diff < -180.0f) angle_diff += 360.0f;
    
    // EMA平滑算法：对角度差进行平滑（平衡新数据响应速度与历史数据稳定性）
    // 公式：平滑差 = α*当前差 + (1-α)*0（历史差默认0，仅依赖当前差与平滑系数）
    float smoothed_diff = EMA_ALPHA * angle_diff + (1 - EMA_ALPHA) * 0.0f;
    // 计算平滑后的角度（基于上一次平滑角度 + 平滑差）
    smoothed_angle = last_smoothed_angle + smoothed_diff;
    // 确保平滑角度在-180° ~ 180°范围
    smoothed_angle = normalize_angle(smoothed_angle);
    
    // 更新历史值
    last_smoothed_angle = smoothed_angle;

    current_angle = smoothed_angle;
    
    rt_kprintf("Smoothed angle: %.2f\n", smoothed_angle);
    
    return smoothed_angle;
}

/*********************
 *  PUBLIC FUNCTIONS
 *********************/

/**
 * @brief  更新角度标签文本（显示当前角度，单位：°）
 * @param  angle - 待显示的角度（单位：0.1°，如900表示90.0°）
 * @retval 无
 */
void update_angle_text(int32_t angle)
{
    // 检查标签是否存在
    if (angle_label == NULL) {
        rt_kprintf("Angle label is NULL\n");
        return;
    }
    
    // 存储格式化后的角度字符串（如"90.0°"）
    char buf[16];
    // 格式化字符串：保留1位小数，添加角度单位°
    snprintf(buf, sizeof(buf), "%0.1f°", angle / 10.0f);
    // 更新LVGL标签文本
    lv_label_set_text(angle_label, buf);
}

/**
 * @brief  更新方向标签文本（显示当前方向，如"North"）
 * @param  index - 方向数组索引（0~7，对应8个方向）
 * @retval 无
 */
void set_direction_text(int index)
{
    // 检查标签是否存在
    if (char_label == NULL) {
        rt_kprintf("Direction label is NULL\n");
        return;
    }
    
    // 检查索引是否有效
    if (index < 0 || index >= 8) {
        rt_kprintf("Invalid direction index: %d\n", index);
        return;
    }
    
    // 定义中英文方向数组
    static const char *chinese_directions[] = {"北", "西北", "西", "西南", "南", "东南", "东", "东北"};
    static const char *english_directions[] = {"North", "Northwest", "West", "Southwest", "South", "Southeast", "East", "Northeast"};
    
    // 构造中英文上下结构的文本（例如："北\nNorth"）
    char buf[32];
    snprintf(buf, sizeof(buf), "%s\n%s", chinese_directions[index], english_directions[index]);
    
    // 更新LVGL标签文本
    lv_label_set_text(char_label, buf);
    // 强制刷新标签（确保界面立即更新）
    lv_obj_invalidate(char_label);
}

/**
 * @brief  指南针指针旋转回调函数（更新指针角度、角度标签、方向标签）
 */
void pointer_rotate_cb(float angle)
{
    // 检查必要的指针
    if (r_dial == NULL /*|| r_dial->compass_pointer == NULL*/) {
        rt_kprintf("UI elements not initialized for rotation\n");
        return;
    }
    
    // 1. 角度归一化：将角度转换到0~3600（对应0°~360°，单位0.1°）
    current_angle_360 = fmodf((angle + 3600.0), 3600.0f);

    rt_kprintf("Angle: %.1f° -> normalized: %.1f\n", angle/10.0f, current_angle_360 / 10.0f);

    // 2. 更新角度显示标签
    update_angle_text((int32_t)current_angle_360);

    // 3. 根据角度判断当前方向（8个方向，每个方向对应450个单位（45°））
    int index;
    if (current_angle_360 >= 0 && current_angle_360 < 450)      index = 0; // 北（0°~45°）
    else if (current_angle_360 >= 450 && current_angle_360 < 900) index = 1; // 西北（45°~90°）
    else if (current_angle_360 >= 900 && current_angle_360 < 1350) index = 2; // 西（90°~135°）
    else if (current_angle_360 >= 1350 && current_angle_360 < 1800) index = 3; // 西南（135°~180°）
    else if (current_angle_360 >= 1800 && current_angle_360 < 2250) index = 4; // 南（180°~225°）
    else if (current_angle_360 >= 2250 && current_angle_360 < 2700) index = 5; // 东南（225°~270°）
    else if (current_angle_360 >= 2700 && current_angle_360 < 3150) index = 6; // 东（270°~315°）
    else                                                          index = 7; // 东北（315°~360°）

    // 4. 更新方向显示标签
    set_direction_text(index);

    rt_kprintf("Setting pointer angle: %d\n", (int32_t)angle);

    // 5. 设置指针旋转角度
    //这个函数内部有断言测试，传入的角度不为0，他会报错，所以这里不应这个，这也是为啥角度不显示的原因
    //lv_img_set_angle(r_dial->compass_pointer, (int32_t)angle);
}



/**
 * @brief  LVGL定时器回调函数（定时更新指南针界面）
 * @param  timer - LVGL定时器对象指针（由LVGL管理）
 * @retval 无
 */
void my_timer(lv_timer_t *timer)
{
    // 检查定时器参数
    if (timer == NULL) {
        rt_kprintf("Timer parameter is NULL\n");
        return;
    }
    
    // 存储从传感器读取的平滑角度
    float sensor_angle = 0;

    // （调试用）记录定时器执行时间（避免耗时过长）
    volatile  rt_tick_t start_tick, end_tick;

    // 1. 读取传感器平滑角度
    sensor_angle = read_sensor_angle();

    rt_kprintf("my_timer sensor_angle=%.2f\n", sensor_angle);

    // 2. 更新指南针UI（使用指针旋转回调函数）
    pointer_rotate_cb(sensor_angle * 10.0f); // 转换为0.1°单位
}

/*********************
 *  UI创建函数
 *********************/

/**
 * @brief 创建指南针用户界面
 */
static void create_compass_ui(void)
{
    // 1. 分配指南针实例内存并初始化（ memset清零，避免野指针）
    r_dial = (Compass *)rt_malloc(sizeof(Compass));
    if (r_dial == NULL) {
        rt_kprintf("Failed to allocate memory for Compass\n");
        return;
    }
    memset(r_dial, 0, sizeof(Compass));

    // 2. 创建指南针表盘（父对象：当前屏幕，lv_scr_act()返回当前活动屏幕）
    r_dial->compass_dial = lv_img_create(lv_scr_act());//指南针的表盘时当前屏幕
    if (r_dial->compass_dial == NULL) {
        rt_kprintf("Failed to create compass dial\n");
        rt_free(r_dial);
        r_dial = NULL;
        return;
    }
    
    // 表盘居中对齐（LV_ALIGN_CENTER：屏幕中心，偏移0,0）
    lv_obj_align(r_dial->compass_dial, LV_ALIGN_CENTER, 0, 0);
    // 设置表盘图片源（使用预定义的表盘图片）
    lv_img_set_src(r_dial->compass_dial, &compass_dial_diagram);

    //关于这块，需要获取屏幕的分辨率在设置吗？这样的话更好调整，也更适用
    // 设置表盘目标尺寸（390x450，需根据屏幕分辨率调整）
    unsigned int obj_width = 350, obj_height = 400; //重新设置尺寸
    // 按目标尺寸缩放表盘图片（避免拉伸）
    lv_obj_img_png_set_zoom(r_dial->compass_dial, &compass_dial_diagram, obj_width, obj_height);

    #if 0
    //因为指针的旋转搞不定，所以取消指针，用文字显示的方式来实现
    // 3. 创建指南针指针（父对象：表盘，确保指针随表盘移动）
    r_dial->compass_pointer = lv_img_create(lv_scr_act());
    if (r_dial->compass_pointer == NULL) {
        rt_kprintf("Failed to create compass pointer\n");
        // 清理已创建的对象
        lv_obj_del(r_dial->compass_dial);
        rt_free(r_dial);
        r_dial = NULL;
        return;
    }
    
    // 初始设置指针图片源
    lv_img_set_src(r_dial->compass_pointer, &compass_pointer_diagram);
    // 指针居中对齐（相对于表盘中心）
    lv_obj_align(r_dial->compass_pointer, LV_ALIGN_CENTER, 0, 0);
    // 设置指针旋转中心点（指针图片的中心，避免旋转时偏移）
    lv_img_set_pivot(r_dial->compass_pointer, compass_pointer_diagram.header.w / 2, compass_pointer_diagram.header.h / 2);
    #endif
    // 4. 创建角度显示标签（父对象：表盘）
    angle_label = lv_label_create(r_dial->compass_dial);
    if (angle_label == NULL) {
        rt_kprintf("Failed to create angle label\n");
        // 清理已创建的对象
        lv_obj_del(r_dial->compass_pointer);
        lv_obj_del(r_dial->compass_dial);
        rt_free(r_dial);
        r_dial = NULL;
        return;
    }
    
    #if 0
    // 设置标签字体为更大更清晰的字体（24号）
    lv_obj_set_style_text_font(angle_label, &lv_font_montserrat_24, 0);
   //因为这个字体比较模糊所以先不用，看看默认字体的效果
   #endif
    
    // 设置标签文字颜色为黑色（确保在白色背景上清晰可见）
    lv_obj_set_style_text_color(angle_label, lv_color_black(), 0);
    // 标签位置：表盘中心上方30像素
    lv_obj_align(angle_label, LV_ALIGN_CENTER, 0, -30);
    // 初始显示角度0°
    update_angle_text(0);

    // 5. 创建方向显示标签（父对象：表盘）
    char_label = lv_label_create(r_dial->compass_dial);
    if (char_label == NULL) {
        rt_kprintf("Failed to create direction label\n");
        // 清理已创建的对象
        lv_obj_del(angle_label);
        lv_obj_del(r_dial->compass_pointer);
        lv_obj_del(r_dial->compass_dial);
        rt_free(r_dial);
        r_dial = NULL;
        return;
    }
    
    // 设置标签字体为更大更清晰的字体（24号）
    //lv_obj_set_style_text_font(char_label, &lv_font_montserrat_24, 0);
    // 设置标签文字颜色为黑色（确保在白色背景上清晰可见）
    lv_obj_set_style_text_color(char_label, lv_color_black(), 0);
    // 标签位置：表盘中心下方30像素
    lv_obj_align(char_label, LV_ALIGN_CENTER, 0, 30);
    
    // 6. 处理指针图片资源
    //handle_img();
}

/*********************
 *   APP LIFECYCLE
 *********************/

static lv_timer_t *compass_timer = NULL;

//应用启动开始跳转到此处执行
static void on_start(void)
{
    rt_kprintf("Compass app starting...\n");//这句打印了
    
    // 初始化传感器在主函数watch_demo.c里
    
    // 创建UI界面
    create_compass_ui();

    // 7. 创建LVGL定时器（定时更新指南针）
    // 定时器回调：my_timer；间隔16ms（约60FPS，界面流畅）；参数NULL；重复次数-1（无限循环）
    //成功返回定时器的对象，用于后边暂停、删除等
    compass_timer = lv_timer_create(my_timer, 100, NULL); // 增加到100ms以减少日志输出，定时器的间隔时间为100ms
    if (compass_timer == NULL) {
        rt_kprintf("Failed to create compass timer\n");
        return;
    }
    
    lv_timer_set_repeat_count(compass_timer, -1);//设置定时器重复次数为-1， 标识无线循环触发

    rt_kprintf("Compass timer created\n");
    lv_img_cache_invalidate_src(NULL);//刷新图片缓存，确保指南针的表盘、指针等图片资源重新加载，避免因缓存残留导致的图片显示异常
    rt_kprintf("Image cache invalidated\n");
}

static void on_pause(void)
{
    // 暂停时停止定时器
    if (compass_timer) {
        lv_timer_pause(compass_timer);//暂停改定时器
        rt_kprintf("Compass timer paused\n");
    }
}

static void on_resume(void)
{
    // 恢复时重启定时器
    if (compass_timer) {
        lv_timer_resume(compass_timer);
        rt_kprintf("Compass timer resumed\n");
    }
}

static void on_stop(void)
{
    // 停止时删除定时器
    if (compass_timer) {
        lv_timer_del(compass_timer);
        compass_timer = NULL;
        rt_kprintf("Compass timer deleted\n");
    }
    
    // 反初始化传感器
    //deinit_sensor();
    
    // 删除UI对象
    if (main_cont) {
        lv_obj_del(main_cont);
        main_cont = NULL;
    }
    
    // 释放指南针对象内存
    if (r_dial) {
        if (r_dial->cp_point) {
            if (r_dial->cp_point->data) {
                rt_free((void*)r_dial->cp_point->data);
            }
            rt_free(r_dial->cp_point);
        }
        rt_free(r_dial);
        r_dial = NULL;
    }
    
    // 清空其他UI指针
    angle_label = NULL;
    char_label = NULL;
    
    rt_kprintf("Compass app stopped\n");
}

//自定义的消息处理函数
static void msg_handler(gui_app_msg_type_t msg, void *param)
{
    switch (msg)
    {
    case GUI_APP_MSG_ONSTART: 
        on_start(); //应用启动时调用，初始化传感器、创建UI界面、启动定时器等等
        break;
    case GUI_APP_MSG_ONRESUME: 
        on_resume(); //应用恢复时调用，恢复传感器、刷新UI界面、恢复定时器等等
        break;
    case GUI_APP_MSG_ONPAUSE: 
        on_pause(); //应用暂停时调用，暂停定时器等等
        break;
    case GUI_APP_MSG_ONSTOP: 
        on_stop(); //应用停止时调用，清理资源，释放内存等等
        break;
    default: 
        break;
    }
}

// 主函数入口
int compass_app_main(intent_t i)
{
    //注册应用的消息处理器，
    gui_app_regist_msg_handler(APP_ID, msg_handler);
    return 0;
}

// 注册一个应用，参数一是应用的标识字符串，给用户界面个系统资源用的；参数二时图标资源， 
//参数三 唯一标识符，用来区分不同的应用； 参数四时程序入口函数
BUILTIN_APP_EXPORT(LV_EXT_STR_ID(compass), LV_EXT_IMG_GET(img_compass), APP_ID, compass_app_main);